package com.yz.fanrenmianshi.blackfilter;
import com.yz.fanrenmianshi.utils.NetUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 全局 IP 黑名单过滤请求拦截器
 * 支持降级策略和严格模式
 */
@Slf4j
@WebFilter(urlPatterns = "/*", filterName = "blackIpFilter")
public class BlackIpFilter implements Filter {
    
    @Value("${blackip.fallback.strict-mode:false}")
    private boolean strictMode;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
                        FilterChain filterChain) throws IOException, ServletException {
        
        String ipAddress = NetUtils.getIpAddress((HttpServletRequest) servletRequest);
        
        try {
            // 检查黑名单
            if (BlackIpUtils.isBlackIp(ipAddress)) {
                log.warn("黑名单IP访问被拦截: {}", ipAddress);
                sendErrorResponse(servletResponse, "-1", "黑名单IP，禁止访问");
                return;
            }
            
            // 如果是严格模式且黑名单服务不可用，可以选择拒绝访问
            if (strictMode && !BlackIpUtils.isServiceAvailable()) {
                log.warn("严格模式下黑名单服务不可用，拒绝访问: {}", ipAddress);
                sendErrorResponse(servletResponse, "-2", "安全服务暂时不可用");
                return;
            }
            
        } catch (Exception e) {
            log.error("黑名单检查异常，IP: {}", ipAddress, e);
            
            // 异常情况下的处理策略
            if (strictMode) {
                // 严格模式：异常时拒绝访问
                sendErrorResponse(servletResponse, "-3", "安全检查异常，禁止访问");
                return;
            }
            // 宽松模式：异常时允许访问，但记录日志
            log.warn("黑名单检查异常，但允许访问: {}", ipAddress);
        }
        
        filterChain.doFilter(servletRequest, servletResponse);
    }
    
    private void sendErrorResponse(ServletResponse servletResponse, String errorCode, String errorMsg) 
            throws IOException {
        servletResponse.setContentType("text/json;charset=UTF-8");
        String jsonResponse = String.format(
            "{\"errorCode\":\"%s\",\"errorMsg\":\"%s\"}", 
            errorCode, errorMsg
        );
        servletResponse.getWriter().write(jsonResponse);
    }
}
